package edu.ubc.javascript;

import com.google.javascript.jscomp.mozilla.rhino.Token;
import com.google.javascript.jscomp.mozilla.rhino.ast.ArrayLiteral;
import com.google.javascript.jscomp.mozilla.rhino.ast.AstNode;
import com.google.javascript.jscomp.mozilla.rhino.ast.AstRoot;
import com.google.javascript.jscomp.mozilla.rhino.ast.Block;
import com.google.javascript.jscomp.mozilla.rhino.ast.BreakStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.CatchClause;
import com.google.javascript.jscomp.mozilla.rhino.ast.ContinueStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.ExpressionStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.FunctionNode;
import com.google.javascript.jscomp.mozilla.rhino.ast.IfStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.KeywordLiteral;
import com.google.javascript.jscomp.mozilla.rhino.ast.Loop;
import com.google.javascript.jscomp.mozilla.rhino.ast.Name;
import com.google.javascript.jscomp.mozilla.rhino.ast.NumberLiteral;
import com.google.javascript.jscomp.mozilla.rhino.ast.ObjectLiteral;
import com.google.javascript.jscomp.mozilla.rhino.ast.ObjectProperty;
import com.google.javascript.jscomp.mozilla.rhino.ast.ReturnStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.StringLiteral;


public class ContextCheck {
	
	public static int translateOp(int op) {
		 switch (op){
	      case Token.ASSIGN_BITOR:
	    	  return Token.BITOR;
	      case Token.ASSIGN_BITXOR:
	    	  return Token.BITXOR;
	      case Token.ASSIGN_BITAND:
	    	  return Token.BITAND;
	      case Token.ASSIGN_LSH:
	    	  return Token.LSH;
	      case Token.ASSIGN_RSH:
	    	  return Token.RSH;
	      case Token.ASSIGN_URSH:
	    	  return Token.URSH;
	      case Token.ASSIGN_ADD:
	    	  return Token.ADD;
	      case Token.ASSIGN_SUB:
	    	  return Token.SUB;
	      case Token.ASSIGN_MUL:
	    	  return Token.MUL;
	      case Token.ASSIGN_DIV:
	    	  return Token.DIV;
	      case Token.ASSIGN_MOD:
	    	  return Token.MOD;
	    }
		throw new IllegalArgumentException();
	}
	
	public static boolean isLValueDescendent(AstNode node) {
		AstNode parent = node.getParent();
		if(parent.getType() == Token.ASSIGN) {
			return true;
		} else if(isRootExpression(parent)) {
			return false;
		} else {
			return isLValueDescendent(parent);
		}
	}
	
	public static boolean isRootExpression(AstNode node) {
		return 	(node instanceof ExpressionStatement) ||
				(node instanceof Block) ||
				(node instanceof IfStatement) ||
				(node instanceof ReturnStatement) ||
				(node instanceof ContinueStatement) ||
				(node instanceof BreakStatement) ||
				(node instanceof FunctionNode) ||
				(node instanceof ObjectLiteral) ||
				(node instanceof ArrayLiteral) ||
				(node instanceof AstRoot);
	}

	public static boolean isIncDec(AstNode node) {
		return 	(node.getType() == Token.INC) ||
				(node.getType() == Token.DEC);
	}
	
	public static boolean isAssignmentOp(int type) {
		    switch (type){
		      case Token.ASSIGN:
		      case Token.ASSIGN_BITOR:
		      case Token.ASSIGN_BITXOR:
		      case Token.ASSIGN_BITAND:
		      case Token.ASSIGN_LSH:
		      case Token.ASSIGN_RSH:
		      case Token.ASSIGN_URSH:
		      case Token.ASSIGN_ADD:
		      case Token.ASSIGN_SUB:
		      case Token.ASSIGN_MUL:
		      case Token.ASSIGN_DIV:
		      case Token.ASSIGN_MOD:
		        return true;
		    }
		    return false;
	}
	
	public static boolean isCompoundStatement(AstNode node) {
		return 	(node instanceof IfStatement) ||
				(node instanceof Loop) ||
				(node instanceof FunctionNode);
	}
	
	public static boolean isAtomicExpression(AstNode node) {
		return 	(node instanceof KeywordLiteral) ||
				(node instanceof FunctionNode) ||
				(node instanceof BreakStatement) ||
				(node instanceof ContinueStatement) ||
				(node instanceof Name) ||
				(node instanceof StringLiteral) ||
				(node instanceof NumberLiteral);
	}
	
	public static boolean isFunctionName(Name name) {
		return name.getParent() instanceof FunctionNode;
	}
	
	public static boolean isCatchObjectName(Name name) {
		return name.getParent() instanceof CatchClause;
	}
	
	public static boolean isVariableReferenceName(Name name) {
		return !isFunctionName(name) && !isCatchObjectName(name);
	}
	
	public static boolean isTopLevel(AstNode node) {
		return (node.getParent() instanceof AstRoot);
	}
}
